package com.finance.report.service;

import com.finance.base.enums.CalculateTypeEnum;
import com.finance.base.enums.FeeCommitStateEnum;
import com.finance.base.enums.MajorTypeEnum;
import com.finance.framework.cache.concurrent.RedisLock;
import com.finance.report.bean.pojo.*;
import com.finance.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;

/**
 * Created by CBWL on 2017/6/13.
 */
@Component
public class SalaryHelper {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private IOrganizationSalaryService organizationSalaryService;
    @Autowired
    private ILogisticsExtendService logisticsExtendService;
    @Autowired
    private ILogisticsErrorLogService logisticsErrorLogService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ManSalaryCommitter manSalaryCommitter;

    @Transactional(rollbackFor = Exception.class,isolation = Isolation.READ_COMMITTED)
    public void commitFee(LogisticsData logisticsData, LogisticsExtend logisticsExtend, BigDecimal fee, CalculateTypeEnum calculateTypeEnum, MajorTypeEnum majorTypeEnum, Long ruleId) throws Exception {
        this.logger.info("运单表拓展数据:{} 运单号：{}",String.valueOf(logisticsExtend),logisticsData.getWaybillNum());
        String lockName = this.genMonth(logisticsData) + logisticsData.getPostmanNo();
        RedisLock lock = new RedisLock(redisTemplate, lockName, 10000, 20000);
        try {
            this.logger.info("锁{}准备加锁",lockName);
            if(lock.lock()) {
                this.logger.info("锁{}加锁成功",lockName);
                this.manSalaryCommitter.updateUserFee(logisticsData,fee,calculateTypeEnum,majorTypeEnum);
                logger.info("已更新员工月表中的数据 员工{}单号{}费用{}",new String[]{logisticsData.getPostmanNo(),logisticsData.getWaybillNum(),String.valueOf(fee)});
                logisticsExtend.setFee(fee);
                this.logger.info("fee值存入对象 fee：{} 运单：{}",String.valueOf(fee),logisticsData.getWaybillNum());
                logisticsExtend.setFeeCommitted(FeeCommitStateEnum.COMMITTED.getState());
                this.logger.info("对象塞值出问题？ FeeCommitted：{} 运单：{} CalculateTyp：{} ruleId：{}",new String[]{String.valueOf(FeeCommitStateEnum.COMMITTED.getState()),logisticsData.getWaybillNum(),String.valueOf(calculateTypeEnum.getValue()),String.valueOf(ruleId)});
                logisticsExtend.setCalculateType(calculateTypeEnum.getValue());
                logisticsExtend.setSectionId(ruleId);
                this.logger.info("salaryHelp[计算后结果更新] {} 运单数据日期：{}",String.valueOf(logisticsExtend),logisticsData.getSignTime());
                this.logisticsExtendService.update(logisticsData.getSignTime(),logisticsExtend);
                this.logger.info("更新完后查库验证 拓展表数据：{} 运单：{}",String.valueOf(this.logisticsExtendService.getByWayBillNum(logisticsData.getSignTime(),logisticsData.getWaybillNum())),logisticsData.getWaybillNum());
                this.logger.info("已更新拓展表单号：{} 费用：{}",new String[]{logisticsExtend.getWaybillNum(),logisticsExtend.getFee() == null ? "未知" : logisticsExtend.getFee().toString()});
                this.logisticsErrorLogService.delete(logisticsData.getSignTime(),logisticsData.getWaybillNum());
            }
        } catch (InterruptedException e) {
            logger.error("锁"+lockName + e.getMessage(),e);
            Thread.currentThread().interrupt();
            throw new Exception(e);
        }finally {
            //为了让分布式锁的算法更稳键些，持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时，再去做DEL操作，因为可能客户端因为某个耗时的操作而挂起，
            //操作完的时候锁因为超时已经被别人获得，这时就不必解锁了。 ————这里没有做
            if(lock.isLocked()) {
                lock.unlock();
            }
            this.logger.info("锁{}已释放",lockName);
        }
    }

    @Transactional
    private boolean updateOrganizationFee(LogisticsData logisticsData, BigDecimal fee, CalculateTypeEnum calculateTypeEnum,MajorTypeEnum majorTypeEnum){
        boolean result = true;
        String month = this.genMonth(logisticsData);
        OrganizationSalary organizationSalary = this.organizationSalaryService.getOrganizationSalaryByOrgCode(logisticsData.getOrgcodeDelivery(),month);
        if(organizationSalary == null){
            organizationSalary = this.genOrganizationSalary(logisticsData,fee,majorTypeEnum);
            result = result && this.organizationSalaryService.addOrganizationSalary(organizationSalary);
        }else{
            organizationSalary = this.freshOrganizationSalary(organizationSalary,logisticsData,fee,majorTypeEnum);
            result = result && this.organizationSalaryService.updateOrganizationSalary(organizationSalary);
        }
        return result;
    }

    private OrganizationSalary genOrganizationSalary(LogisticsData logisticsData, BigDecimal fee, MajorTypeEnum majorTypeEnum) {
        OrganizationSalary organizationSalary = new OrganizationSalary();
        organizationSalary.setVersion(0);
        organizationSalary.setSalaryMonth(genMonth(logisticsData));
        organizationSalary.setTotalFee(fee);
        organizationSalary.setOrganizationCode(logisticsData.getOrgcodeDelivery());
        if(majorTypeEnum == MajorTypeEnum.MAJOR){
            organizationSalary.setMajorFee(fee);
            organizationSalary.setMajorCount(1);
            organizationSalary.setMinorCount(0);
            organizationSalary.setMinorFee(new BigDecimal(0));
        }else if(majorTypeEnum == MajorTypeEnum.DRAG){
            organizationSalary.setMinorCount(1);
            organizationSalary.setMinorFee(fee);
            organizationSalary.setMajorFee(new BigDecimal(0));
            organizationSalary.setMajorCount(0);
        }
        return organizationSalary;
    }

    private OrganizationSalary freshOrganizationSalary(OrganizationSalary organizationSalary,LogisticsData logisticsData, BigDecimal fee,MajorTypeEnum majorTypeEnum){
        organizationSalary.setTotalFee(organizationSalary.getTotalFee().add(fee));
        if(majorTypeEnum == MajorTypeEnum.MAJOR){
            organizationSalary.setMajorFee(organizationSalary.getMajorFee().add(fee));
            organizationSalary.setMajorCount(organizationSalary.getMajorCount()+1);
        }else if(majorTypeEnum == MajorTypeEnum.DRAG){
            organizationSalary.setMinorCount(organizationSalary.getMinorCount()+1);
            organizationSalary.setMinorFee(organizationSalary.getMinorFee().add(fee));
        }
        return organizationSalary;
    }

    public String genMonth(LogisticsData logisticsData){
        return DateUtil.dateFormat(logisticsData.getSignTime(),"yyyy-MM");
    }
}
